//
// Created on 2022/11/16.
//
// Node APIs are not fully supported. To solve the compilation error of the interface cannot be found,
// please include "napi/native_api.h".

#include <native_drawing/drawing_font_collection.h>
#include "napi/font/drawing_register_font.h"
#include "TextBitmap.h"
#include "napi/helper/NapiHelper.h"
#include "napi/file/RawFileUtils.h"

TextBitmap *TextBitmap::createCCTextBitmap(const char *text, const char *pFontName, const const char *fAlignment,
                                              int width_, int height_, double fontSize) {
    return createCCTextBitmap(text, pFontName, fontSize, 255, 0, 0, 0, fAlignment, width_, height_, false, 1, 1, 1,
                              false, 1, 1, 1, 1);
}

TextBitmap *TextBitmap::createCCTextBitmap(const char *text, const char *pFontName, const float a, const float r,
                                              const float g, const float b, const const char *fAlignment, int width_,
                                              int height_, double fontSize) {
    return createCCTextBitmap(text, pFontName, fontSize, a, r, g, b, fAlignment, width_, height_, false, 1, 1, 1, false,
                              1, 1, 1, 1);
}

    int TextBitmap::processTextAlign(const char *fAlignment) {
        // 水平展示
        int align = TEXT_ALIGN_LEFT;
        if (strcmp(fAlignment, "right") ==0) {
            align = TEXT_ALIGN_RIGHT;
        } else if (strcmp(fAlignment, "center")==0) {
            align = TEXT_ALIGN_CENTER;
        }
        return align;
    }

    TextBitmap *TextBitmap::createCCTextBitmap(const char *text, const char *pFontName, const int fontSize,
                                               const float fontTintA, const float fontTintR, const float fontTintG,
                                               const float fontTintB, const char *fAlignment, const int pWidth,
                                               const int pHeight, const bool shadow, const float shadowDX,
                                               const float shadowDY, const float shadowBlur, const bool stroke,
                                               const float strokeR, const float strokeG, const float strokeB,
                                               const float strokeSize) {
        TextBitmap *cCTextBitmap = new TextBitmap();
        // Manages typographical styles, such as text orientation.
        cCTextBitmap->_typographyStyle = OH_Drawing_CreateTypographyStyle();
        // Set the text to be displayed from left to right.
        OH_Drawing_SetTypographyTextDirection(cCTextBitmap->_typographyStyle, TEXT_DIRECTION_LTR);
        int align = processTextAlign(fAlignment);
        // Set text alignment
        OH_Drawing_SetTypographyTextAlign(cCTextBitmap->_typographyStyle, align);
        // Used to load fonts
        /****** the font collection will be destructed while creating typo graphy handler 
            in the future version 230 or later, this api will be deprecated; 
            use the new api, this pointer will not be deleted while creating the handler****/
        cCTextBitmap->_fontCollection = OH_Drawing_CreateFontCollection(); // will be deprecated in the feature

        const char *fontFamilies[] = {pFontName};
        if (pFontName == nullptr) {
            fontFamilies[0] = "HarmonyOS Sans";
        }
    
        if ( pFontName && !RawFileUtils::GetInstance().fileIsExistInWriteablePath(pFontName) && RawFileUtils::GetInstance().fileIsExistInRawPath(pFontName) ) {
            const char *fileFontPath = RawFileUtils::GetInstance().copyRawFile2WriteablePath(pFontName);
            OH_Drawing_RegisterFont(cCTextBitmap->_fontCollection, pFontName, fileFontPath);
        }
    
        // Creates a pointer to the OH_Drawing_TypographyCreate object
        cCTextBitmap->_typographyCreate =
            OH_Drawing_CreateTypographyHandler(cCTextBitmap->_typographyStyle, cCTextBitmap->_fontCollection);
    
        // Used to manage font colors, decorations, etc.
        cCTextBitmap->_textStyle = OH_Drawing_CreateTextStyle();

        // Set Text Color
        OH_Drawing_SetTextStyleColor(cCTextBitmap->_textStyle,
                                     OH_Drawing_ColorSetArgb(fontTintA, fontTintR, fontTintG, fontTintB));
        // Set text size
        OH_Drawing_SetTextStyleFontSize(cCTextBitmap->_textStyle, fontSize == 0 ? DEFAULT_FONTSIZE : fontSize);
        // Set word weight
        OH_Drawing_SetTextStyleFontWeight(cCTextBitmap->_textStyle, FONT_WEIGHT_400);
        // Set the font baseline position. TEXT_BASELINE_ALPHABotic is used to display phonetic characters and the
        // baseline position is lower in the middle. TEXT_BASELINE_IDEOGRAPHIC for ideographic text with baseline
        // atbottom
        OH_Drawing_SetTextStyleBaseLine(cCTextBitmap->_textStyle, TEXT_BASELINE_ALPHABETIC);
        // Set font height
        OH_Drawing_SetTextStyleFontHeight(cCTextBitmap->_textStyle, 1);

        // Set the font type
        OH_Drawing_SetTextStyleFontFamilies(cCTextBitmap->_textStyle, 1, fontFamilies);
        // Set the font style. The font style is not italicized. FONT_EVEN_ITALIC Italic
        OH_Drawing_SetTextStyleFontStyle(cCTextBitmap->_textStyle, FONT_STYLE_NORMAL);
        // Setting the Language Area
        OH_Drawing_SetTextStyleLocale(cCTextBitmap->_textStyle, "en");

        // Set the typesetting style
        OH_Drawing_TypographyHandlerPushTextStyle(cCTextBitmap->_typographyCreate, cCTextBitmap->_textStyle);
        // Set text content
        OH_Drawing_TypographyHandlerAddText(cCTextBitmap->_typographyCreate, text);
        // Typesetting pop-up
        OH_Drawing_TypographyHandlerPopTextStyle(cCTextBitmap->_typographyCreate);

        // Used to create OH_Drawing_Typography, which is used to manage the layout and display of typesetting.
        cCTextBitmap->_typography = OH_Drawing_CreateTypography(cCTextBitmap->_typographyCreate);

        // The input width of the outer layer is preferentially used. If the input width is not used, the calculated width is used.
        int layoutWidth = pWidth;
        if (pWidth == 0) {
            // In NAPI mode, call the ArkTS function to calculate the text width. Here, 400 is the word weight, which corresponds to the value of OH_Drawing_SetTextStyleFontWeight.
            layoutWidth = JSFunction::getFunction("StringUtils.getWidth").invoke<int>(text, fontSize, 400);
        }
    
        OH_Drawing_TypographyLayout(cCTextBitmap->_typography, layoutWidth);

        // Obtains the maximum inherent width.
        int realWidth = OH_Drawing_TypographyGetMaxIntrinsicWidth(cCTextBitmap->_typography);
        if (pWidth == 0) {
            // In NAPI mode, call the ArkTS function to calculate the text width. Here, 400 is the word weight, which corresponds to the value of OH_Drawing_SetTextStyleFontWeight.
            layoutWidth = realWidth;
        }

        // typographic layout, setting maximum text width
        int paddingSize = 4 - layoutWidth % 4;
        if (paddingSize != 4) {
            layoutWidth += paddingSize;
        }
    
        // Obtaining the height
        int realHeight = OH_Drawing_TypographyGetHeight(cCTextBitmap->_typography);
        int layoutHeight = pHeight;
        if(pHeight == 0){
            layoutHeight = realHeight;
        }
    
        // Format used to describe the bit pixel, including color type and transparency type.
        cCTextBitmap->_bitmap = OH_Drawing_BitmapCreate();
        // COLOR_FORMAT_RGBA_8888：Each pixel is represented by a 32-bit quantity. 8 bits indicate transparency, 8 bits
        // indicate red, 8 bits indicate green, and 8 bits indicate blue. ALPHA_FORMAT_OPAQUE：Bitmap has no
        // transparency
        OH_Drawing_BitmapFormat cFormat = {COLOR_FORMAT_ALPHA_8, ALPHA_FORMAT_OPAQUE};

        // Initializes the width and height of the bitmap object, and sets the pixel format for the bitmap.
        OH_Drawing_BitmapBuild(cCTextBitmap->_bitmap, layoutWidth, layoutHeight, &cFormat);

        // Create a canvas object
        cCTextBitmap->_canvas = OH_Drawing_CanvasCreate();
        // Bind a bitmap object to the canvas so that the content drawn on the canvas is output to the bitmap (i.e., CPU
        // rendering).
        OH_Drawing_CanvasBind(cCTextBitmap->_canvas, cCTextBitmap->_bitmap);
    
        // Uses the specified color to clear the canvas. OH_Drawing_ColorSetArgb: Converts four variables (respectively
        // describing transparency, red, green, and blue) to a 32-bit (ARGB) variable that describes colors.
        OH_Drawing_CanvasClear(cCTextBitmap->_canvas, OH_Drawing_ColorSetArgb(0x00, 0xFF, 0x00, 0x00));
        // Display Text
        OH_Drawing_TypographyPaint(cCTextBitmap->_typography, cCTextBitmap->_canvas, 0, 0);

        constexpr uint32_t stride = 1;
        // Obtains the pixel address of a specified bitmap. The pixel data of the bitmap can be obtained based on
        // thepixel address.
        cCTextBitmap->pixelAddr = OH_Drawing_BitmapGetPixels(cCTextBitmap->_bitmap);
        cCTextBitmap->width = layoutWidth;
        cCTextBitmap->height = layoutHeight;
        cCTextBitmap->bufferSize = layoutWidth * layoutHeight * stride;

        return cCTextBitmap;
    }

    void *TextBitmap::getPixelAddr() { return pixelAddr; }

    TextBitmap::~TextBitmap() {
        OH_Drawing_CanvasDestroy(_canvas);
        //  OH_Drawing_BitmapDestroy(_bitmap);
        OH_Drawing_DestroyTypographyStyle(_typographyStyle);
        OH_Drawing_DestroyTextStyle(_textStyle);
        OH_Drawing_DestroyTypographyHandler(_typographyCreate);
        OH_Drawing_DestroyTypography(_typography);
        OH_Drawing_DestroyFontCollection(_fontCollection);

        pixelAddr = nullptr;
    }